/**
 * @author Marina Polese
 *
 */

package capture;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import javax.swing.JOptionPane;

import jpcap.JpcapCaptor;
import jpcap.PacketReceiver;
import jpcap.packet.IPPacket;
import jpcap.packet.Packet;
import view.FrameWork;

public class Captor {

	public static Preferences preferences;
	private long MAX_PACKETS_HOLD = 10000;
	private List<Packet> packets = new ArrayList<Packet>();
	private JpcapCaptor jpcap = null;
	private boolean isLiveCapture;
	private FrameWork frame = null;
	private ExecutorService exe = Executors.newFixedThreadPool(10);
	public static final Map<InetAddress,String> hostnameCache = new HashMap<InetAddress, String>();
	private Thread captureThread;

	public Captor(FrameWork frame){
		this.frame = frame;
		preferences = Preferences.userNodeForPackage(Captor.class);
	}

	public void setFrame(FrameWork frame){
		this.frame=frame;
	}

	public List<Packet> getPackets(){
		return packets;
	}

	public void capturePacketsFromDevice() {
		if(jpcap!=null)
			jpcap.close();
		jpcap = CaptureDialog.getJpcap(frame);
		clear();

		if (jpcap != null) {
			frame.disableCapture();
			isLiveCapture = true;
			frame.getButtonStopCapture();

			startCaptureThread();
		}
	}

	public void stopCapture() {
		stopCaptureThread();
	}

	private void clear(){
		packets.clear();
		frame.getCapturePanel().clearAll();
	}

	private void startCaptureThread() {
		if (captureThread != null)
			return;

		captureThread = new Thread(new Runnable(){
			public void run() {
				while (captureThread != null) {
					if (jpcap.processPacket(1, handler) == 0 && !isLiveCapture)
						stopCaptureThread();
					Thread.yield();
				}
				jpcap.breakLoop();
				frame.getButtonStartCapture();
			}
		});
		captureThread.setPriority(Thread.MIN_PRIORITY);

		frame.startUpdating();
		captureThread.start();
	}

	void stopCaptureThread() {
		captureThread = null;
		frame.stopUpdating();
	}

	private PacketReceiver handler = new PacketReceiver(){
		public void receivePacket(final Packet packet) {
			packets.add(packet);
			while (packets.size() > MAX_PACKETS_HOLD) {
				packets.remove(0);
			}

			if(packet instanceof IPPacket){
				exe.execute(new Runnable(){
					public void run() {
						IPPacket ip=(IPPacket)packet;
						if(!hostnameCache.containsKey(ip.src_ip))
							hostnameCache.put(ip.src_ip,ip.src_ip.getHostName());
						if(!hostnameCache.containsKey(ip.dst_ip))
							hostnameCache.put(ip.dst_ip,ip.dst_ip.getHostName());
					}
				});
			}
		}
	};

	public FrameWork getFrame() {
		return frame;
	}

	public static void saveProperty(){
		try{
			preferences.flush();
		} catch (BackingStoreException e) {
			JOptionPane.showMessageDialog(null,"Impossibile salvare le preferenze.",
					"Error",JOptionPane.ERROR_MESSAGE);
		}
	}

}
